package com.qfedu.common.exception.handler;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.qfedu.common.WoException;
import com.qfedu.common.entity.WoResultCode;
import com.qfedu.common.util.WoConstant;
import com.qfedu.common.util.WoUtil;

@Component
public class WoControllerExceptionHandler {

	private final static Logger LOG = LogManager.getLogger(WoControllerExceptionHandler.class);

	public final static String MSG_KEY_SUCC = "msg";
	
	public final static String MSG_KEY_FAIL = "error";
	
	/**
	 * @param error
	 * @return
	 */
	public static String getErrorQueryString (String error) {
		try {
			return "error=" + URLEncoder.encode(error, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new WoException (e, WoConstant.ERR_URL_ENCODING);
		}
	}
	
	/**
	 * @param msg
	 * @return
	 */
	public static String getSuccessQueryString (String msg) {
		try {
			return "msg=" + URLEncoder.encode(msg, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new WoException (e, WoConstant.ERR_URL_ENCODING);
		}
	}
	
	/**
	 * get请求html异常时，跳转的视图名称
	 */
	@Value("${wo.view.error}")
	private String getErrorView;

	/**
	 * ajax请求html页面异常时，跳转的视图名称
	 */
	@Value("${wo.view.error.ajax}")
	private String ajaxErrorView;

	/**
	 * 异常时需要跳转到登录页面视图名称
	 */
	@Value("${wo.view.login}")
	private String loginViewName;

	/**
	 * 异常时跳转到failureView，成功时的视图由cb返回
	 * @param cb
	 * @param map
	 * @param failureView
	 * @param unknown
	 * @return
	 */
	public String toView(CallBackObject cb, Map<String, Object> map, String failureView, String unknown) {
		if (WoUtil.isEmpty(unknown)) {
			unknown = "操作失败！";
		}
		try {
			return cb.callService().toString();
		} catch (Exception e) {
			LOG.error("", e);
			String error = null;
			if (e instanceof WoException) {
				error = e.getMessage();
			} else {
				error = unknown;
			}
			if (!failureView.startsWith("redirect:")) {
				map.put(MSG_KEY_FAIL, error);
			} else {
				failureView += "?" + getErrorQueryString (error);
			}
			return failureView;
		}
	}
	
	/**
	 * 处理请求html页面异常
	 * 
	 * @param map
	 * @param successView
	 *            成功视图
	 * @param failureView
	 *            失败视图
	 * @param unknown
	 *            未知失败的消息
	 * @param cb
	 *            该接口中的方法调用service方法
	 * @return
	 */
	public String toView(CallBack cb, Map<String, Object> map, String successView, String failureView, String unknown) {
		if (WoUtil.isEmpty(unknown)) {
			unknown = "操作失败！";
		}
		try {
			cb.callService();
			return successView;
		} catch (Exception e) {
			LOG.error("", e);
			String error = null;
			if (e instanceof WoException) {
				error = e.getMessage();
			} else {
				error = unknown;
			}
			if (!failureView.startsWith("redirect:")) {
				map.put(MSG_KEY_FAIL, error);
			} else {
				try {
					failureView += "?error=" + URLEncoder.encode(error, "UTF-8");
				} catch (UnsupportedEncodingException e1) {
					LOG.warn("编码错误信息失败！", e1);
				}
			}
			return failureView;
		}
	}

	/**
	 * 处理请求html页面异常
	 * 
	 * @param map
	 * @param successView
	 *            成功视图
	 * @param failureView
	 *            失败视图
	 * @param cb
	 *            该接口中的方法调用service方法
	 * @return
	 */
	public String toView(CallBack cb, Map<String, Object> map, String successView, String failureView) {
		return this.toView(cb, map, successView, failureView, "操作失败！");
	}

	/**
	 * 处理get请求html页面异常，并跳转到登录页面
	 * 
	 * @param map
	 * @param successView
	 *            成功视图
	 * @param cb
	 *            该接口中的方法调用service方法
	 * @return
	 */
	public String toLoginView(CallBack cb, Map<String, Object> map, String successView) {
		return this.toView(cb, map, successView, loginViewName, "认证失败！");
	}

	/**
	 * 处理get请求html页面异常
	 * 
	 * @param map
	 * @param successView
	 *            成功视图
	 * @param unknown
	 *            未知失败的消息
	 * @param cb
	 *            该接口中的方法调用service方法
	 * @return
	 */
	public String toErrorView(CallBack cb, Map<String, Object> map, String successView, String unknown) {
		return this.toView(cb, map, successView, getErrorView, unknown);
	}

	/**
	 * 处理get请求html页面异常
	 * 
	 * @param map
	 * @param successView
	 *            成功视图
	 * @param cb
	 *            该接口中的方法调用service方法
	 * @return
	 */
	public String toErrorView(CallBack cb, Map<String, Object> map, String successView) {
		return this.toView(cb, map, successView, getErrorView, "操作失败！");
	}

	/**
	 * 处理ajax请求html页面异常
	 * 
	 * @param map
	 * @param successView
	 *            成功视图
	 * @param unknown
	 *            未知失败的消息
	 * @param cb
	 *            该接口中的方法调用service方法
	 * @return
	 */
	public String toAjaxErrorView(CallBack cb, Map<String, Object> map, String successView,
			String unknown) {
		return this.toView(cb, map, successView, ajaxErrorView, unknown);
	}

	/**
	 * 处理ajax请求html页面异常
	 * 
	 * @param map
	 * @param successView
	 *            成功视图
	 * @param cb
	 *            该接口中的方法调用service方法
	 * @return
	 */
	public String toAjaxErrorView(CallBack cb, Map<String, Object> map, String successView) {
		return this.toView(cb, map, successView, ajaxErrorView, "操作失败！");
	}

	/**
	 * 处理Controller中调用Service方法产生的异常，并将消息设置到共享域
	 * 
	 * @param map
	 * @param success
	 *            成功消息
	 * @param unknown
	 *            未知失败的消息
	 * @param cb
	 *            该接口中的方法调用service方法
	 */
	public void setMessage(CallBack cb, Map<String, Object> map, String success, String unknown) {
		if (WoUtil.isEmpty(success)) {
			success = "操作成功！";
		}
		if (WoUtil.isEmpty(unknown)) {
			unknown = "操作失败！";
		}
		try {
			cb.callService();
			map.put(MSG_KEY_SUCC, success);
		} catch (Exception e) {
			LOG.error("", e);
			if (e instanceof WoException) {
				map.put(MSG_KEY_FAIL, e.getMessage());
			} else {
				map.put(MSG_KEY_FAIL, unknown);
			}
		}
	}

	/**
	 * 处理Controller中调用Service方法产生的异常，并将消息设置到共享域
	 * 
	 * @param map
	 * @param cb
	 *            该接口中的方法调用service方法
	 */
	public void setMessage(CallBack cb, Map<String, Object> map) {
		this.setMessage(cb, map, "操作成功！", "操作失败！");
	}

	/**
	 * @param unknown
	 * @param cb
	 * @return
	 */
	public Object toJsonView(CallBackObject cb, String unknown) {
		if (WoUtil.isEmpty(unknown)) {
			unknown = "操作失败！";
		}
		try {
			return cb.callService();
		} catch (Exception e) {
			LOG.error("", e);
			if (e instanceof WoException) {
				return ((WoException) e).getCode();
			} else {
				return WoResultCode.getUnknownCode().setMsg(unknown);
			}
		}
	}

	/**
	 * @param cb
	 * @return
	 */
	public Object toJsonView(CallBackObject cb) {
		return toJsonView(cb, null);
	}

	/**
	 * @param unknown
	 * @param cb
	 * @return
	 */
	public WoResultCode toJsonView(CallBack cb, String success, String unknown) {
		try {
			cb.callService();
			WoResultCode re = WoResultCode.getSuccessCode();
			if (!WoUtil.isEmpty(success)) {
				re.setMsg(success);
			}
			return re;
		} catch (Exception e) {
			LOG.error("", e);
			if (e instanceof WoException) {
				return ((WoException) e).getCode();
			} else {
				WoResultCode re = WoResultCode.getUnknownCode();
				if (!WoUtil.isEmpty(unknown)) {
					re.setMsg(unknown);
				}
				return re;
			}
		}
	}

	/**
	 * @param success
	 * @param cb
	 * @return
	 */
	public WoResultCode toJsonView(CallBack cb, String success) {
		return this.toJsonView(cb, success, null);
	}

	/**
	 * 调用service方法，没有返回值
	 * @author cailei
	 *
	 */
	public static interface CallBack {
		/**
		 * 在此方法中调用Service的方法。
		 */
		public void callService();
	}

	/**
	 * 调用service方法，有返回值
	 * @author cailei
	 *
	 */
	public static interface CallBackObject {
		/**
		 * 在此方法中调用Service的方法。
		 */
		public Object callService();
	}
}
